/*************************************************************************
	> File Name: server.c
	> Author: ma6174
	> Mail: ma6174@163.com 
	> Created Time: 2016年08月01日 星期一 12时12分46秒
 ************************************************************************/
#include "common.h"
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <sys/time.h>
//0.正常打印提示信息， 1.错误打印
int printf_flag = 1;

void *ss_talk(void *arg);

typedef struct{
	char type;
	char fromname[10];
	char toname[10];
	char chat_data[1024];
	struct sockaddr_in addr;
}RECV_MSG;
typedef struct{
	char flag;
	int num;
	char namelist[10][10];
	char fromname[10];
	char chat_data[1024];
	struct sockaddr_in addr;
}SEND_MSG;
typedef struct{
	struct sockaddr_in * cli_addr;
	char username[50];
	int sockfd;
	int flag;
	struct list_head list;
}NODE;

//表驱动法，结构体，结构体数组
typedef struct{
	char type;
	void (*pfun)(RECV_MSG *recv_msg_p, NODE *node);
}EVENT_DRIVE;
void func2(RECV_MSG *recv_msg_p, NODE *node);
void func3(RECV_MSG *recv_msg_p, NODE *node);
void func4(RECV_MSG *recv_msg_p, NODE *node);
//2:聊天  3:保活 4:发文件
//func2: 服务器聊天处理函数
//func3: 服务器保活处理函数
//func4: 服务器发文件处理函数
const EVENT_DRIVE driveTable[] = {{2, func2}, {3, func3}, {4, func4}};


struct list_head LinkList;


void *judge_heart(void *arg)
{
	while(1)
	{
		struct list_head *pos4;
		NODE *node4 = NULL;
		list_for_each(pos4,&LinkList)
		{
			node4 = list_entry(pos4, NODE, list);
			if(node4->flag == 0)
			{
				//free, list_del, close
				close(node4->sockfd);
				list_del(pos4);
				free(node4);
			}
			if(node4->flag == 1)
				node4->flag = 0;
		}
		sleep(600);
	}
	return NULL;
}

int adduser(int sockfd,struct sockaddr_in *cliaddr);
int main(void)
{
	//注册段错误处理函数，方便调试
	//signal(SIGSEGV, signal_handler);
	
	//监听套接字
	int sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if(sockfd < 0)
		err_sys("socket error");

	//服务器地址结构体
	struct sockaddr_in server_addr;
	bzero(&server_addr,sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(9999);
	inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);

	
	//在bind之前，设置SO_REUSEADDR选项
	int sockopt = 1;
	if((setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt))) < 0)
		err_sys("setsockopt error");
	
	//绑定服务器地址结构
	int ret;
	ret = bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
	if(ret != 0)
		err_sys("bind error");

	//监听套接字
	ret = listen(sockfd, 10);
	if(ret != 0)
		err_sys("listen error");

	//创建线程ss_talk与本机运行的另一个进程ss通信（进程间通信）（比如设置打印级别，发送打印用户列表命令，踢掉某个用户）
	pthread_t tid;
	pthread_create(&tid, NULL, ss_talk, NULL);
	pthread_detach(tid);

	//初始化链表
	INIT_LIST_HEAD(&LinkList);
	
	//创建线程	判断保活标志flag==0
	pthread_t tid2;
	pthread_create(&tid2, NULL, judge_heart, NULL);
	pthread_detach(tid2);

	int maxfd = sockfd + 1;
	fd_set read_set;
	FD_ZERO(&read_set);
	while(1)
	{
		FD_ZERO(&read_set);
		FD_SET(sockfd, &read_set);
		//循环链表FD_SET(sockfd, connfd)
		
		struct list_head *pos3;
		NODE *node3 = NULL;
		list_for_each(pos3,&LinkList)
		{
			node3 = list_entry(pos3, NODE, list);
			FD_SET(node3->sockfd, &read_set);
		}
			
		select(maxfd, &read_set, NULL, NULL, NULL);
		
		
		if(FD_ISSET(sockfd, &read_set))
		{	
			struct sockaddr_in *cliaddr = (struct sockaddr_in*)malloc(sizeof(struct sockaddr_in));
			socklen_t cliaddr_len = sizeof(struct sockaddr_in);
			int connfd;
			connfd = accept(sockfd, (struct sockaddr*)cliaddr, &cliaddr_len);
			if(connfd < 0)
				err_sys("accept error");
				if(adduser(connfd,cliaddr))
				{
					if(connfd > maxfd -1)
						maxfd = connfd + 1;			
					if(printf_flag == 0)
						printf("add success!\n");	
				}
			else
			{
				if(printf_flag == 1)
					err_sys("accept error");
				else
					err_sys("");

			}
			continue;
		}
		
		//遍历链表的connfd， FD_ISSET(connfd, &read_set);
		struct list_head *pos;
		NODE *node = NULL;
		list_for_each(pos,&LinkList)
		{
			 node = list_entry(pos, NODE, list);
		
			 if(FD_ISSET(node->sockfd, &read_set))
			{

				//聊天，转发数据
				 RECV_MSG recv_msg;
				 bzero(&recv_msg, sizeof(recv_msg));
				 int ret;
				 ret = recv(node->sockfd, &recv_msg, sizeof(recv_msg), 0);
				 if(printf_flag == 0)
				 {
					char buffname1[10] = "";
					strncpy(buffname1, recv_msg.fromname, strlen(recv_msg.fromname)-1);
					char buffname2[10] = "";
					strncpy(buffname2, recv_msg.toname, strlen(recv_msg.toname)-1);					
					printf("fromname:%s toname:%s type:%d data:%s\n", buffname1, buffname2, recv_msg.type, recv_msg.chat_data);
				 }
				 if(ret == 0){
					 
					SEND_MSG send_msg1;
					bzero(&send_msg1, sizeof(send_msg1));
					send_msg1.flag = 8;
					strncpy(send_msg1.fromname, node->username, strlen(node->username));
	
					struct list_head *pos6;
					NODE *node6 = NULL;
					list_for_each(pos6,&LinkList)
					{
						node6 = list_entry(pos6, NODE, list);
						if(strncmp(node6->username, node->username, strlen(node->username)) != 0)
							send(node6->sockfd, &send_msg1, sizeof(send_msg1), 0);
					}						 
					 close(node->sockfd);
					 list_del(&(node->list));
					 free(node);
					 continue;
				 }
				int i;
				for(i = 0; i < sizeof(driveTable)/sizeof(EVENT_DRIVE); i++)
				{
					if(driveTable[i].type == recv_msg.type)
					{
						driveTable[i].pfun(&recv_msg, node);
						break;
					}
				}
			}
		 }
	 }
}
int adduser(int sockfd,struct sockaddr_in *cliaddr)
{
	RECV_MSG recv_msg;
	SEND_MSG send_msg;
	bzero(&recv_msg, sizeof(recv_msg));
	bzero(&send_msg, sizeof(send_msg));
	recv(sockfd,&recv_msg,sizeof(recv_msg),0);
	if(list_empty(&LinkList))
	{
		 NODE *node = (NODE *)malloc(sizeof(NODE));
		 node->cli_addr = cliaddr;
		 strcpy(node->username,recv_msg.fromname);
		 node->sockfd = sockfd;
		 list_add(&node->list,&LinkList);
		 send_msg.flag = 1;
		 send_msg.num = 0;
		 strcpy(send_msg.namelist[0],recv_msg.fromname);
		 send(sockfd,&send_msg,sizeof(send_msg),0);
	}
	else
	{
		struct list_head *pos;
		NODE *node1 = NULL;
		list_for_each(pos,&LinkList)
		{
			node1 = list_entry(pos, NODE, list);
			if(strncmp(node1->username,recv_msg.fromname,strlen(node1->username)) == 0)
			{
				send_msg.flag = 0;
				send(sockfd,&send_msg,sizeof(send_msg),0);
				return 0;
			}
			strcpy(send_msg.namelist[send_msg.num++],node1->username);
		}
		NODE *node = (NODE *)malloc(sizeof(NODE));
		node->cli_addr = cliaddr;
		strcpy(node->username, recv_msg.fromname);
		node->sockfd = sockfd;
		list_add(&node->list,&LinkList);
		send_msg.flag = 1;
		send(sockfd,&send_msg,sizeof(send_msg),0);
	}
	
	//添加一个聊天记录文件，以username为名
	//创建或打开两个文件,文件名:send_msg.fromname, recv_msg_p->toname., 		fd = open(name, O_RDWR|O_CREAT|O_APPEND, 0777);
//	printf("name:%s strlen:%d\n", recv_msg.fromname, strlen(recv_msg.fromname));
//	char filename[10] = "";
//	strncpy(filename, recv_msg.fromname, strlen(recv_msg.fromname) - 1);
	int fd = open(recv_msg.fromname, O_RDWR|O_CREAT|O_APPEND, 0777);
	if(fd < 0 && printf_flag == 1)
		err_sys("create file error");
	if(fd < 0)
		err_sys("");
	close(fd);
	
	
	//告知之前的客户端 该新用户上线了，flag = 7
	SEND_MSG send_msg1;
	bzero(&send_msg1, sizeof(send_msg1));
	send_msg1.flag = 7;
	strncpy(send_msg1.fromname, recv_msg.fromname, strlen(recv_msg.fromname));
	
	struct list_head *pos6;
	NODE *node6 = NULL;
	list_for_each(pos6,&LinkList)
	{
		node6 = list_entry(pos6, NODE, list);
		if(strncmp(node6->username, recv_msg.fromname, strlen(recv_msg.fromname)) != 0)
			send(node6->sockfd, &send_msg1, sizeof(send_msg1), 0);
	}	
	return 1;
}

void func4(RECV_MSG *recv_msg_p, NODE *node)
{
	//遍历查找用户链表，是否有用户名与msg.toname一样
	if(strncmp(recv_msg_p->chat_data,"trans file",strlen("trans file")) == 0)
	{
		struct list_head *pos3;
		NODE *node3 = NULL;
		list_for_each(pos3,&LinkList)
		{
			node3 = list_entry(pos3, NODE, list);
			if(strncmp(recv_msg_p->toname, node3->username, strlen(recv_msg_p->toname)) == 0)
			{
				SEND_MSG send_msg;
				bzero(&send_msg,sizeof(send_msg));
				send_msg.flag = 4;
				sprintf(send_msg.chat_data,"accept from %s file?",recv_msg_p->fromname);
				strcpy(send_msg.fromname, recv_msg_p->fromname);
				send(node3->sockfd, &send_msg, sizeof(send_msg), 0);
				break;
			}
		}
		if(pos3 == &LinkList)
		{
			SEND_MSG send_msg;
			bzero(&send_msg,sizeof(send_msg));
			send_msg.flag = 3;
			strcpy(send_msg.chat_data, "no such name\n");
			send(node->sockfd, &send_msg, sizeof(send_msg), 0);
		}
	}
	else if(strncmp(recv_msg_p->chat_data,"y",strlen("y")) == 0)
	{
		struct list_head *pos3;
		NODE *node3 = NULL;
		list_for_each(pos3,&LinkList)
		{
			node3 = list_entry(pos3, NODE, list);
			if(strncmp(recv_msg_p->toname, node3->username, strlen(recv_msg_p->toname)) == 0)
			{
				SEND_MSG send_msg;
				bzero(&send_msg,sizeof(send_msg));
				send_msg.flag = 5;
				memcpy(&send_msg.addr,&(recv_msg_p->addr),sizeof(send_msg.addr));
				strcpy(send_msg.chat_data,"star connect");
				strcpy(send_msg.fromname, recv_msg_p->fromname);
				send(node3->sockfd, &send_msg, sizeof(send_msg), 0);
				break;
			}
		}
		if(pos3 == &LinkList)
		{
			SEND_MSG send_msg;
			bzero(&send_msg,sizeof(send_msg));
			send_msg.flag = 3;
			strcpy(send_msg.chat_data, "no such name\n");
			send(node->sockfd, &send_msg, sizeof(send_msg), 0);
		}
	}
	else
	{
		struct list_head *pos3;
		NODE *node3 = NULL;
		list_for_each(pos3,&LinkList)
		{
			node3 = list_entry(pos3, NODE, list);
			if(strncmp(recv_msg_p->toname, node3->username, strlen(recv_msg_p->toname)) == 0)
			{
				SEND_MSG send_msg;
				bzero(&send_msg,sizeof(send_msg));
				send_msg.flag = 6 ;
				strcpy(send_msg.chat_data,"input error or confuse your request");
				strcpy(send_msg.fromname, recv_msg_p->fromname);
				send(node3->sockfd, &send_msg, sizeof(send_msg), 0);
				break;
			}
		}
		if(pos3 == &LinkList)
		{
			SEND_MSG send_msg;
			bzero(&send_msg,sizeof(send_msg));
			send_msg.flag = 3;
			strcpy(send_msg.chat_data, "no such name\n");
			send(node->sockfd, &send_msg, sizeof(send_msg), 0);
		}						
	}
}
void func2(RECV_MSG *recv_msg_p, NODE *node)
{
	//聊天结束stop，
	if(strncmp(recv_msg_p->chat_data, "stop", strlen("stop")) == 0 && strncmp(recv_msg_p->toname, "server", strlen("server")) == 0)	
	{
		//关闭套接字，从链表中删除该用户
		close(node->sockfd);
		struct list_head *pos1;
		NODE *node1 = NULL;
		list_for_each(pos1,&LinkList)
		{
			node1 = list_entry(pos1, NODE, list);
			if(strncmp(recv_msg_p->fromname, node1->username, strlen(recv_msg_p->fromname)) == 0)
			{
				
				SEND_MSG send_msg1;
				bzero(&send_msg1, sizeof(send_msg1));
				send_msg1.flag = 7;
				strncpy(send_msg1.fromname, recv_msg_p->fromname, strlen(recv_msg_p->fromname));
	
				struct list_head *pos6;
				NODE *node6 = NULL;
				list_for_each(pos6,&LinkList)
				{
					node6 = list_entry(pos6, NODE, list);
					if(strncmp(node6->username, recv_msg_p->fromname, strlen(recv_msg_p->fromname)) != 0)
						send(node6->sockfd, &send_msg1, sizeof(send_msg1), 0);
				}					
				
				if(printf_flag == 0)
					printf("delete sockfd\n");
				list_del(pos1);	
				free(node1);
				return;
			}
		}
	} 
	
	//聊天记录，发送客户端
	if(strncmp(recv_msg_p->chat_data, "history", strlen("history")) == 0 && strncmp(recv_msg_p->toname, "server", strlen("server")) == 0)	
	{	
		int fd9 = open(recv_msg_p->fromname, O_RDWR|O_CREAT|O_APPEND, 0777);
//		if(fd < 0)
		int num11;
//		char buff_history[1024] = "";
//		num11 = read(fd, send_msg11.chat_data, sizeof(send_msg11.chat_data));
		SEND_MSG send_msg11;
		bzero(&send_msg11, sizeof(SEND_MSG));
		send_msg11.flag = 9;
		num11 = read(fd9, send_msg11.chat_data, sizeof(send_msg11.chat_data));
		while(num11 > 0)
		{
			send(node->sockfd, &send_msg11, sizeof(send_msg11), 0);
			num11 = read(fd9, send_msg11.chat_data, sizeof(send_msg11.chat_data));
		}
		close(fd9);
	}	

	
	//遍历查找用户链表，是否有用户名与msg.toname一样
	struct list_head *pos2;
	NODE *node2 = NULL;
	list_for_each(pos2,&LinkList)
	{
		node2 = list_entry(pos2, NODE, list);
		if(strncmp(recv_msg_p->toname, node2->username, strlen(recv_msg_p->toname)) == 0)
		{
			SEND_MSG send_msg;
			bzero(&send_msg,sizeof(send_msg));
			send_msg.flag = 2;
			strcpy(send_msg.chat_data, recv_msg_p->chat_data);
			strcpy(send_msg.fromname, recv_msg_p->fromname);
			send(node2->sockfd, &send_msg, sizeof(send_msg), 0);
			//创建或打开两个文件,文件名:send_msg.fromname, recv_msg_p->toname., 		fd = open(name, O_RDWR|O_CREAT|O_APPEND, 0777);
			// char data[1024];			sprintf(data, "%s to %s: %s\n", send_fromname, recv_msg_p->chat_data, recv_msg_p->toname);
			//							write(fd, data, strlen(data));
			int fd1 = open(recv_msg_p->toname, O_RDWR|O_CREAT|O_APPEND, 0777);
			int fd2 = open(send_msg.fromname, O_RDWR|O_CREAT|O_APPEND, 0777);
			char data[1024] = "";
			char buffname1[10] = "";
			char buffname2[10] = "";
			time_t tt = time(NULL);
			char tt_char[100] = "";
			//tt_char = ctime(&tt);
			strcpy(tt_char, ctime(&tt));
			strncpy(buffname1, send_msg.fromname, strlen(send_msg.fromname)-1);
			strncpy(buffname2, recv_msg_p->toname, strlen(recv_msg_p->toname)-1);
			sprintf(data, "%s%s to %s: %s\n", tt_char, buffname1, buffname2, recv_msg_p->chat_data);
			//			sprintf(data, "%s to %s: %s\n", send_msg.fromname, recv_msg_p->toname, recv_msg_p->chat_data);
			write(fd1, data, strlen(data));
			write(fd2, data, strlen(data));
			close(fd1);
			close(fd2);
			break;
		}
	}
//	printf("pos:%p\n", pos2);
//	printf("linklist:%p\n", &LinkList);
	if(pos2 == &LinkList)
	{
		SEND_MSG send_msg;
		bzero(&send_msg,sizeof(send_msg));
		send_msg.flag = 3;
		strcpy(send_msg.chat_data, "no such name\n");
		send(node->sockfd, &send_msg, sizeof(send_msg), 0);
	}

}
void func3(RECV_MSG *recv_msg_p, NODE *node)
{
	node->flag = 1;
}

void *ss_talk(void *arg)
{
        int ssfd;
        ssfd = socket(AF_INET, SOCK_STREAM, 0);
        if(ssfd < 0 && printf_flag == 1)
                err_sys("ssfd socket error");
        if(ssfd < 0)
                err_sys("");
        struct sockaddr_in myaddr;
        bzero(&myaddr, sizeof(myaddr));
        myaddr.sin_family = AF_INET;
        myaddr.sin_port = htons(8888);
        myaddr.sin_addr.s_addr = htonl(INADDR_ANY);

		//在bind之前，设置SO_REUSEADDR选项
		int sockopt = 1;
		if((setsockopt(ssfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt))) < 0 && printf_flag == 1)
			err_sys("setsockopt error");		
		if((setsockopt(ssfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt))) < 0)
				err_sys("");				
		
        int ret2;
        ret2 = bind(ssfd, (struct sockaddr*)&myaddr, sizeof(myaddr));
        if(ret2 != 0 && printf_flag == 1)
                err_sys("ss bind error");
        if(ret2 != 0)
                err_sys("");

        ret2 = listen(ssfd, 2);
        if(ret2 != 0 && printf_flag == 1)
                err_sys("ss listen error");
        if(ret2 != 0)
                err_sys("");

        printf("ss listening...\n");

        while(1)
        {
                struct sockaddr_in ssaddr;
                char ssip[INET_ADDRSTRLEN] = {0};
                socklen_t ssaddr_len = sizeof(ssaddr);

                int connssfd;
                connssfd = accept(ssfd, (struct sockaddr*)&ssaddr, &ssaddr_len);
                if(connssfd < 0 && printf_flag == 1)
                        err_sys("ss accept error");
                if(connssfd < 0)
                        err_sys("");

                inet_ntop(AF_INET, &ssaddr.sin_addr, ssip, INET_ADDRSTRLEN);
                if(printf_flag == 0)
					printf("\nss connected\n");

				int flag22 = 0;//判断ss有没有正确输入指令的标志

                char recv_ss_cmd[100];
                while(recv(connssfd, recv_ss_cmd, 100, 0) > 0)
                {
                        if(printf_flag == 0)
						{
							printf("recv ss ok!\n");
							printf("cmd is %s\n", recv_ss_cmd);
						}
                        int m = 0;

						//打印所有在线用户
						if(strncmp(recv_ss_cmd, "printf", strlen("printf")) == 0)
                        {
							if(printf_flag == 0)
                                printf("cmd ok1\n"); 
								struct list_head *pos;
                                NODE *node = NULL;
								
                                list_for_each(pos, &LinkList)
                                {
 								 	if(m == 0 && printf_flag == 0)
										printf("online users:\n");

							        node = list_entry(pos, NODE, list);
									if(printf_flag == 0)
										printf("%s",node->username);
						            send(connssfd, node->username, strlen(node->username), 0);
									m++;
									
                                }
								m = 0;
								flag22 = 1;
								memset(&recv_ss_cmd, 0, sizeof(recv_ss_cmd));

                        }

                        //强制某用户下线
                        if(strncmp(recv_ss_cmd, "delete", 6) == 0)
                        {
                                 //将命令拆分为delete和name
								int delete_flag = 0;
                                char *p;
                                char del_name[50];
                                p = strtok(recv_ss_cmd, " ");
                                p = strtok(NULL, " ");
                                strcpy(del_name, p);
								del_name[strlen(del_name)] = '\0';
					

                                //遍历查找用户链表，是否有用户名和del_name一样
                                struct list_head *pos;
                                NODE *node = NULL;
                                list_for_each(pos, &LinkList)
                                {
                                         node = list_entry(pos, NODE, list);
								
                                        if(strncmp(del_name, node->username, strlen(node->username)) == 0)
                                        {
											close(node->sockfd);
                                            list_del(pos);
                                            free(node);
											delete_flag++;//若成功删除，则flag+1
                                            break;
                                        }
                                }
								if(delete_flag == 1)
									printf("delete successfully\n");
								else
									printf("username not found\n");
								delete_flag = 0;
								flag22 = 1;
								memset(&recv_ss_cmd, 0, sizeof(recv_ss_cmd));
                        }

						//设置打印级别printf_flag 0或1
						if(strncmp(recv_ss_cmd, "p_level ", strlen("p_level")) == 0)
						{
							//将命令拆分为 p_level 和 0或1
							char level_num[5];
							char *p;
							p = strtok(recv_ss_cmd, " ");
							p = strtok(NULL, " ");
							strcpy(level_num, p);
							level_num[strlen(level_num)] = '\0';
							
							if(strncmp(level_num, "0", 1) == 0)
							{
								printf_flag = 0;
								printf("打印级别设置为 0，打印提示信息\n");
							}
							else
								printf("打印级别设置为 1，打印错误信息\n");

							flag22 = 1;
							memset(&recv_ss_cmd, 0, sizeof(recv_ss_cmd));
						}

                        //关闭ss调试程序
                        if(strncmp(recv_ss_cmd, "stop", strlen("stop")) == 0)
                        {
                                 shutdown(ssfd, SHUT_WR);
								close(connssfd);
								if(printf_flag == 0){
									printf("ss closed\n");
									printf("ss_server closed\n");
								}
								flag22 = 1;
								memset(&recv_ss_cmd, 0, sizeof(recv_ss_cmd));
                                continue;
                        }
						
						//当子服务器从ss接收到其他命令时
						if(flag22 == 0)
						{
							if(printf_flag == 0)
								printf("ss cmd error\n");
							memset(&recv_ss_cmd, 0, sizeof(recv_ss_cmd));
						}
						flag22 = 0;
				}
		}
}